二叉排序树
- 二叉排序树的定义
二叉排序树(BST)也称为二叉查找树。非空二叉排序树满足:- 若左子树非空,则左子树上所有结点关键字值均小于根结点的关键字值。
- 若右子树非空,则右子树所有结点关键字值均大于根结点的关键字值。
- 左右子树本身也是一颗二叉排序树。
对二叉排序树进行中序遍历可以得到一个递增序列。
- 二叉排序树的查找
设欲查找值为K,将K与根结点的关键字值比较,若相对则查找成功,若其值大于K则在根结点的左子树中查找,若其值小于K则在根结点的右子树中查找。1
2
3
4
5
6
7
8BSTNode *BST_Serach(BiTree T,ElemType key){
while(T&&key!=T->data){
if(key>T->data)
T=T->rchild;
else T=T->lchild;
}
return T;
}
二叉排序树的插入
若二叉排序树为空,则直接插入结点;若关键字k小于根结点的关键字,则插入到左子树中,若关键字k大于根结点的关键字,则插入到右子树中。1
2
3
4
5
6
7
8
9
10
11
12
13
14int BST_Insert(BiTree &T,ElemType k){
if(T==NULL){ //若树为空直接插入
T=(BiTree)malloc(sizeof(BiNode));
T->data=k;
T->lchild=T->rchild=NULL;
return 1;
}
else if(T->data==K) //若关键字k已存在,插入失败
return 0;
else if(T->data>k) //插入左子树
return BST_Insert(T->lchild,k);
else //插入右子树
return BST_Insert(T->rchild,k);
}二叉排序树的构造
构造二叉排序树就是将一个一个元素插入到二叉排序树中1
2
3
4
5
6
7
8void Create_BST(BiTree &T,ElemType array[],int n){
T=NULL; //初始化空树
i=0;
while(i<n){
BST_Insert(T,array[i]);
i++;
}
}二叉排序树的删除
删除结点时要将断开的二叉链表重新链接。
具体方法:- 若删除结点时叶子结点,直接删除
- 若删除结点z只有一颗左子树或右子树,则让z的子树代替z的位置
- 若删除结点z既有左子树又有右子树,则另z的直接前驱(或直接后继)替代z,再删除原来的直接前驱(或直接后继)
【注:直接前驱或直接后继指排序序列中离z最近的左右两个结点】
二叉排序树的查找效率
二叉排序树的查找性能与树的高度有关,若二叉排序树是只有左孩子的单子树,其平均查找长度为O(n),若为平衡二叉树则平均查找长度为O(log2n)。
平衡二叉树
平衡二叉树的定义
左右子树高度差的绝对值不超过1的二叉树称为平衡二叉树(AVL树),定义左子树与右子树的高度差为该结点的平衡因子,平衡因子取值为{-1,0,1}。平衡二叉树的插入
插入方法:若插入结点导致平衡二叉树失衡,找到离插入结点最近的失衡结点A,对以A为根的子树进行调整,使其重新平衡。
失衡调整规律:- LL平衡旋转(右单旋转):结点A的左孩子的左子树上插入新结点导致失衡,需要一次右旋操作,将A的左孩子右旋代替A。
- RR平衡旋转(左单旋转):与LL平衡旋转相反。
- LR平衡旋转(先左后右双旋转):结点A的左孩子B的右子树C上插新结点导致失衡。需要两次旋转,先将C左旋到B的位置,再将C右旋到A的位置
- RL平衡旋转(先右后左双旋转):与LR平衡旋转相反。
平衡二叉树的查找
平均查找长度O(log2n)。
哈夫曼树和哈夫曼编码
哈夫曼树的定义
结点的权:一个数值
结点的带权路径长度:根到该结点的路径长度与其权值的乘积。
树的带权路径长度(WPL):树中所有叶子结点的带权路径长度之和。
带权路径长度最小的二叉树称为哈夫曼树,也称为最优二叉树。哈夫曼树的构造
1
2
3
41. N个结点作为N棵树构成森林F
2. 构造新结点,其左右子树为F中根结点权值最小的两棵树,其权值为左右子树根结点的权值之和。
3. 删除上步骤所选两棵树,将新树加入F
4. 重复2、3步骤直到只剩下一棵树。哈夫曼编码
对一字符串序列,将每个出现的字符作为一个结点,其权值为该字符的出现频率,构造出对应哈夫曼树。在哈夫曼树中,转向左孩子的边标记为0,转向右孩子的边标记为1,则各个字符的编码为根到该字符的路径上边标记的序列。